package com.luxf.base.domainevent.configuration;

import com.luxf.base.domainevent.DefaultDomainEventNoticeHandler;
import com.luxf.base.domainevent.DomainEventNoticeHandler;
import com.luxf.base.domainevent.EventNoticeManager;
import com.luxf.base.domainevent.annotation.AggregateRootIdChecker;
import com.luxf.base.domainevent.codec.GsonMessageDecoder;
import com.luxf.base.domainevent.codec.GsonMessageEncoder;
import com.luxf.base.domainevent.codec.MessageDecoder;
import com.luxf.base.domainevent.codec.MessageEncoder;
import com.luxf.base.domainevent.eventtype.EventTypeConfigurer;
import com.luxf.base.domainevent.eventtype.EventTypeLoader;
import com.luxf.base.domainevent.eventtype.SimpleEventTypeLoader;
import com.luxf.base.domainevent.utils.DomainEventUtils;
import com.luxf.base.domainevent.utils.SpringContextUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.util.List;
import java.util.Optional;

/**
 * @author fast66
 * 2021-05-27 8:36
 **/
@EnableJpaRepositories(basePackages = {"com.luxf"})
@EntityScan(basePackages = {"com.luxf"})
@EnableScheduling
public class DomainEventConfiguration {

    /**
     * The configurers for {@link EventTypeLoader}.
     */
    private final List<EventTypeConfigurer> eventTypeConfigurers;

    public DomainEventConfiguration(ObjectProvider<List<EventTypeConfigurer>> eventTypeConfigurers) {
        this.eventTypeConfigurers = eventTypeConfigurers.getIfAvailable();
    }

    @Bean
    public DomainEventNoticeHandler domainEventNoticeHandler() {
        return new DefaultDomainEventNoticeHandler();
    }

    @Bean
    public DomainEventUtils domainEventUtils() {
        return new DomainEventUtils();
    }

    @Bean
    public SpringContextUtils springContextUtils() {
        return new SpringContextUtils();
    }

    @Bean
    @ConditionalOnMissingBean(MessageEncoder.class)
    public MessageEncoder gsonMessageEncoder() {
        return new GsonMessageEncoder();
    }

    @Bean
    @ConditionalOnMissingBean(MessageDecoder.class)
    public MessageDecoder gsonMessageDecoder() {
        return new GsonMessageDecoder();
    }

    @Bean
    public EventNoticeManager domainEventNoticeStatusManager() {
        return new EventNoticeManager();
    }

    @Bean
    public AggregateRootIdChecker aggregateIdentifierAnnotationChecker() {
        return new AggregateRootIdChecker();
    }

    @Bean
    public DomainEventEnvironment domainEventEnvironment() {
        return new DomainEventEnvironment();
    }

    @Bean
    @ConditionalOnMissingBean
    public EventTypeLoader simpleEventTypeLoader() {
        EventTypeLoader eventTypeLoader = new SimpleEventTypeLoader();
        Optional.ofNullable(eventTypeConfigurers)
                .ifPresent(configurers ->
                        configurers.forEach(configurer ->
                                configurer.configure(eventTypeLoader)));
        return eventTypeLoader;
    }

}
